package com.zh.yqbj.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.unit.DataSizeUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zh.yqbj.constant.StatusConstant;
import com.zh.yqbj.dto.SpaceDTO;
import com.zh.yqbj.entity.Note;
import com.zh.yqbj.entity.Space;
import com.zh.yqbj.entity.SpaceNote;
import com.zh.yqbj.entity.UserSpace;
import com.zh.yqbj.mapper.SpaceMapper;
import com.zh.yqbj.service.NoteService;
import com.zh.yqbj.service.SpaceNoteService;
import com.zh.yqbj.service.SpaceService;
import com.zh.yqbj.service.UserSpaceService;
import com.zh.yqbj.util.FileSizeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户空间表 服务实现类
 * </p>
 *
 * @author zh
 * @since 2024-03-27 03:49:56
 */
@Service
@Slf4j
public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space> implements SpaceService {
    @Autowired
    private SpaceMapper spaceMapper;
    @Autowired
    private UserSpaceService userSpaceService;
    @Autowired
    private SpaceNoteService spaceNoteService;
    @Autowired
    private NoteService noteService;

    @Override
    public List<Tree<String>> getLoginUserSpaces() {
        //未登录获取空
        if (!StpUtil.isLogin()) {
            return new ArrayList<>();
        }
        // 是看自己的
        String userId = StpUtil.getLoginIdAsString();
        // 构建node列表
        List<String> userSpaceIds = userSpaceService.list(new LambdaQueryWrapper<UserSpace>().eq(UserSpace::getUserId
                , userId).eq(UserSpace::getStatus, StatusConstant.STATUS_NORMAL)).stream().map(UserSpace::getSpaceId).collect(Collectors.toList());
        List<Space> spaceList = new ArrayList<>();
        SpaceService spaceService = (SpaceService) AopContext.currentProxy();
        if (CollUtil.isNotEmpty(userSpaceIds)) {
            spaceList = spaceService.list(new LambdaQueryWrapper<Space>().in(Space::getId, userSpaceIds));
        }
        //2.配置
        TreeNodeConfig config = new TreeNodeConfig();
        config.setIdKey("id");
        config.setNameKey("spaceName");
        config.setParentIdKey("parentId");
//        没有精力去计算层次
//        config.setDeep(3);
        config.setChildrenKey("children");
        List<Tree<String>> treeList = TreeUtil.build(spaceList, "0", config, (treeNode, tree) -> {
            tree.setId(treeNode.getId());
            tree.setParentId(treeNode.getParentId());
            tree.setName(treeNode.getSpaceName());
            // 扩展属性 ...
            tree.putExtra("key", treeNode.getId());
            tree.putExtra("spaceSize", treeNode.getSpaceSize());
            tree.putExtra("spaceDesc",treeNode.getSpaceDesc());
            tree.putExtra("type", treeNode.getType());
            // 查出该空间下的笔记
            List<String> noteIds = spaceNoteService.list(new LambdaQueryWrapper<SpaceNote>()
                            .eq(SpaceNote::getSpaceId, treeNode.getId())
                            .eq(SpaceNote::getStatus, StatusConstant.STATUS_NORMAL))
                    .stream()
                    .map(SpaceNote::getNoteId)
                    .collect(Collectors.toList());
            List<Note> noteList = new ArrayList<>();
            //mybatis-plus未做处理，只能手动判空
            if (CollUtil.isNotEmpty(noteIds)) {
                noteList = noteService.listByIds(noteIds);
            }
            tree.putExtra("noteList", noteList);
        });
        return treeList;
    }

    @Override
    public List<Space> getLoginUserRootSpaces() {
        //未登录获取空
        if (!StpUtil.isLogin()) {
            return new ArrayList<>();
        }
        String userId = StpUtil.getLoginIdAsString();
        List<String> spaceIds = userSpaceService.list(new LambdaQueryWrapper<UserSpace>().eq(UserSpace::getUserId,
                userId).eq(UserSpace::getStatus, StatusConstant.STATUS_NORMAL)).stream().map(UserSpace::getSpaceId).collect(Collectors.toList());
        //根
        List<Space> spaceList = new ArrayList<>();
        SpaceService spaceService = (SpaceService) AopContext.currentProxy();
        if (CollUtil.isNotEmpty(spaceIds)) {
            spaceList = spaceService.list(new LambdaQueryWrapper<Space>().eq(Space::getParentId, 0).in(Space::getId,
                    spaceIds));
        }
        return spaceList;
    }

    @Override
    public List<Tree<String>> getSpaceTree(String spaceId) {
        //未登录获取空
        if (!StpUtil.isLogin()) {
            return new ArrayList<>();
        }
        // 是看自己的
        String userId = StpUtil.getLoginIdAsString();
        // 构建node列表
        List<String> userSpaceIds = userSpaceService.list(new LambdaQueryWrapper<UserSpace>().eq(UserSpace::getUserId
                , userId).eq(UserSpace::getStatus, StatusConstant.STATUS_NORMAL)).stream().map(UserSpace::getSpaceId).collect(Collectors.toList());
        List<Space> spaceList = new ArrayList<>();
        SpaceService spaceService = (SpaceService) AopContext.currentProxy();
        if (CollUtil.isNotEmpty(userSpaceIds)) {
            spaceList = spaceService.list(new LambdaQueryWrapper<Space>().in(Space::getId, userSpaceIds));
        }
        // 获取父级id
        String parentId = this.getById(spaceId).getParentId();
        //2.配置
        TreeNodeConfig config = new TreeNodeConfig();
        config.setIdKey("id");
        config.setNameKey("spaceName");
        config.setParentIdKey("parentId");
//        没有精力去计算层次
//        config.setDeep(3);
        config.setChildrenKey("children");
        List<Tree<String>> treeList = TreeUtil.build(spaceList, parentId, config, (treeNode, tree) -> {
            tree.setId(treeNode.getId());
            tree.setParentId(treeNode.getParentId());
            tree.setName(treeNode.getSpaceName());
            // 扩展属性 ...
            tree.putExtra("key", treeNode.getId());
            tree.putExtra("spaceSize", treeNode.getSpaceSize());
            tree.putExtra("spaceDesc",treeNode.getSpaceDesc());
            tree.putExtra("type", treeNode.getType());
            // 查出该空间下的笔记
            List<String> noteIds = spaceNoteService.list(new LambdaQueryWrapper<SpaceNote>()
                            .eq(SpaceNote::getSpaceId, treeNode.getId())
                            .eq(SpaceNote::getStatus, StatusConstant.STATUS_NORMAL))
                    .stream()
                    .map(SpaceNote::getNoteId)
                    .collect(Collectors.toList());
            List<Note> noteList = new ArrayList<>();
            //mybatis-plus未做处理，只能手动判空
            if (CollUtil.isNotEmpty(noteIds)) {
                noteList = noteService.listByIds(noteIds);
            }
            tree.putExtra("noteList", noteList);
        });
        return treeList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSpaceWithUser(Space space) {
        spaceMapper.insert(space);
        // 添加用户空间关联
        UserSpace userSpace = new UserSpace();
        userSpace.setUserId(StpUtil.getLoginIdAsString());
        userSpace.setSpaceId(space.getId());
        userSpace.setCreateTime(LocalDateTimeUtil.now());
        userSpace.setUpdateTime(LocalDateTimeUtil.now());
        userSpaceService.save(userSpace);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSpace(SpaceDTO spaceDTO) {
        //0. 史山的代价，处理id
        if(spaceDTO.getId()!=null){
            spaceDTO.setSpaceId(spaceDTO.getId());
        }
        //1. 更新修改时间
        SpaceService spaceService = (SpaceService) AopContext.currentProxy();
        LambdaUpdateWrapper<UserSpace> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserSpace::getSpaceId, spaceDTO.getSpaceId());
        updateWrapper.set(UserSpace::getUpdateTime, LocalDateTimeUtil.now());
        //2. 更新用户-空间表
        userSpaceService.update(updateWrapper);
        //3. 更新空间其他信息
        Space newSpace = BeanUtil.copyProperties(spaceDTO, Space.class, "id");
        newSpace.setId(spaceDTO.getSpaceId());
        spaceService.updateById(newSpace);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSpace(String spaceId) {
        //1. 修改用户空间表的status为1，因为有三种状态，所以不能用mp逻辑删除插件
        // 2. 有孩子不能杀
        SpaceService spaceService = (SpaceService) AopContext.currentProxy();
        List<String> spaceIds =
                spaceService.list(new LambdaQueryWrapper<Space>().eq(Space::getParentId, spaceId)).stream().map(Space::getId).collect(Collectors.toList());
        if (!spaceIds.isEmpty()) {
            List<UserSpace> userSpaceList = userSpaceService.list(new LambdaQueryWrapper<UserSpace>()
                    .eq(UserSpace::getStatus, StatusConstant.STATUS_NORMAL)
                    .in(UserSpace::getSpaceId, spaceIds));
            if (!userSpaceList.isEmpty()) {
                return;
            }
        }
        LambdaUpdateWrapper<UserSpace> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserSpace::getSpaceId, spaceId);
        updateWrapper.eq(UserSpace::getStatus, StatusConstant.STATUS_NORMAL);
        updateWrapper.set(UserSpace::getStatus, StatusConstant.STATUS_DELETE);
        updateWrapper.set(UserSpace::getUpdateTime, LocalDateTimeUtil.now());
        userSpaceService.update(updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeSpace(String spaceId) {
        LambdaUpdateWrapper<UserSpace> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserSpace::getSpaceId, spaceId);
        updateWrapper.eq(UserSpace::getStatus, StatusConstant.STATUS_DELETE);
        updateWrapper.set(UserSpace::getStatus, StatusConstant.STATUS_REMOVE);
        updateWrapper.set(UserSpace::getUpdateTime, LocalDateTimeUtil.now());
        userSpaceService.update(updateWrapper);
    }

    @Override
    public void recycleSpace(String spaceId) {
        LambdaUpdateWrapper<UserSpace> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserSpace::getSpaceId, spaceId);
        updateWrapper.eq(UserSpace::getStatus, StatusConstant.STATUS_DELETE);
        updateWrapper.set(UserSpace::getStatus, StatusConstant.STATUS_NORMAL);
        updateWrapper.set(UserSpace::getUpdateTime, LocalDateTimeUtil.now());
        userSpaceService.update(updateWrapper);
    }
    @Override
    public void calcSpaceSize(String spaceId) {
        SpaceService spaceService = (SpaceService) AopContext.currentProxy();
        //拿出本空间笔记
        List<String> noteIds = spaceNoteService.list(new LambdaQueryWrapper<SpaceNote>()
                        .eq(SpaceNote::getSpaceId, spaceId)
                        .eq(SpaceNote::getStatus, StatusConstant.STATUS_NORMAL))
                .stream()
                .map(SpaceNote::getNoteId)
                .collect(Collectors.toList());
        long noteSize = 0;
        // 没有笔记，笔记大小为0
        if (!noteIds.isEmpty()) {
            List<String> contentList =
                    noteService.listByIds(noteIds).stream().map(Note::getContent).collect(Collectors.toList());
            for (String content : contentList) {
                noteSize += content.getBytes().length;
            }
        }
        // 拿出本空间的一级子空间 status = 0
        List<Space> spaceList = spaceService.list(new LambdaQueryWrapper<Space>().eq(Space::getParentId, spaceId));
        long spaceSize = 0;
        if (!spaceList.isEmpty()) {
            for (Space space : spaceList) {
                UserSpace one = userSpaceService.getOne(new LambdaQueryWrapper<UserSpace>()
                        .eq(UserSpace::getSpaceId,
                                space.getId()).eq(UserSpace::getStatus, StatusConstant.STATUS_NORMAL));
                if (one == null) {
                    spaceList.remove(space);
                }
                String size = space.getSpaceSize();
                spaceSize += FileSizeUtil.formatSizeToBytes(size);
            }
        }
        String totalSize = DataSizeUtil.format(noteSize + spaceSize);
        if ("0".equals(totalSize)) {
            totalSize = "0 B";
        }
        spaceService.update(new LambdaUpdateWrapper<Space>().eq(Space::getId, spaceId).set(Space::getSpaceSize,
                totalSize));
    }

    @Override
    public void calcAllSpaceSize(List<String> spaceIds) {
        SpaceService spaceService = (SpaceService) AopContext.currentProxy();
        for (String spaceId : spaceIds) {
            spaceService.calcSpaceSize(spaceId);
        }
    }


}
